#Pablo Estrada 12121
#Alberto Suriano 12281
#Hoja de Trabajo #5

#importando bibliotecas o librerias
from SimPy.Simulation import *
from random import Random, randint

#declaración de la clase Banco que servirá para la simulación
class Banco(Process):
    #Constructor
    def __init__(self,id):
        Process.__init__(self)
        self.id=id
    
    #metodo que servirá para poder definir lo que pasa cuando se atiende a un cliente  
    def atenderCliente(self,tiempoLlegada,tiempoBanco):
        yield hold,self,tiempoLlegada
        self.llega = now()
        #Eligiendo ventanilla a usar:
        # Escogera la que tenga menor numero de clientes

        clientes_en_ventanilla = [ len(ventanillas[0].waitQ) + len(ventanillas[0].activeQ),len(ventanillas[1].waitQ) + len(ventanillas[1].activeQ),
                                   len(ventanillas[2].waitQ) + len(ventanillas[2].activeQ),
                                   len(ventanillas[3].waitQ) + len(ventanillas[3].activeQ),
                                   len(ventanillas[4].waitQ) + len(ventanillas[4].activeQ),
                                   len(ventanillas[5].waitQ) + len(ventanillas[5].activeQ),
                                   len(ventanillas[6].waitQ) + len(ventanillas[6].activeQ),
                                   len(ventanillas[7].waitQ) + len(ventanillas[7].activeQ)]
        
        for i in range(8): #hay 4 ventanillas
            if clientes_en_ventanilla[i] == 0 or clientes_en_ventanilla[i] == min(clientes_en_ventanilla):
                self.ventanilla = i  #se escoje la ventanilla con menor numero de clientes pues la cola es menor
                break
        #Mostrando estado del proceso cuando se esta esperando
        print ("El cliente # ",self.id," hace cola en Ventanilla ", self.ventanilla )   
        yield request,self,ventanillas[self.ventanilla] #esperamos pasar por la ventanilla
        print ("%5.1f %s Decide entrar en la ventanilla %d" %(now(),self.id, self.ventanilla))
        yield hold, self, tiempoBanco      # nos tardamos 1 unidad de tiempo haciendo cola
        print ("%5.1f %s pasa a la ventanilla %d" %(now(),self.id, self.ventanilla))
        yield release, self, ventanillas[self.ventanilla]

         #Mostrando el estao del proceso al ser atendido el cliente
        yield request,self,clientesEnAtencion
        print ("%5.1f %s Obtiene un espacio para atencion" %(now(),self.id))
        yield hold,self,
        tiempoTotal = now() - self.llega
        wt.observe(tiempoTotal)
        print ("%5.1f %s Sale del banco %5.1f Tiempo total= %5.1f" %(now(),self.id,tiempoBanco,tiempoTotal))
        yield release,self,clientesEnAtencion 

#variables para la simulacion
wt=Monitor()
initialize()
numClientes=200
clientesEnAtencion=Resource(capacity=4,qType=FIFO)
#Se definen 4 ventanillas. Se colocan en una lista para poder hacer escalable el programa
ventanillas = [Resource(capacity=1,name="Ventanilla1"), Resource(capacity=1,name="Ventanilla2"),Resource(capacity=1,name="Ventanilla3"),Resource(capacity=1,name="Ventanilla4"),Resource(capacity=1,name="Ventanilla5"),Resource(capacity=1,name="Ventanilla6"),Resource(capacity=1,name="Ventanilla7"),Resource(capacity=1,name="Ventanilla8")]
r = Random(12345)

#ciclo para simulacion
for i in range(numClientes):
    c=Banco(id="Cliente"+ str(i))
    activate(c,c.atenderCliente(tiempoLlegada= r.randint(1,480),tiempoBanco= r.randint(1,30)))
simulate(until=1000)

#mostrando estado
print ("Tiempo total en las Ventanillas: \tmean = %5.1f, \n\t\tvariance=%2d"%(wt.mean(),wt.var()))
